package com.tansun.rule.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ObjectUtils;

import java.text.ParseException;
import java.util.*;

/**
 * 20200102 ljt
 * 规则计算中请求报文json字符串与map之间的互相转换
 */
public class RuleMapAndJsonUtils {

    /**
     * 将入参json转化为规则计算所需要的insertMap
     * @param json
     * @param metaMap
     * @return
     * @throws Exception
     */
    public static Map<String, Object> jsonCoverMap(Map<String,Object> businessInputMap, 
    		Map<String, MClass> metaMap,
    		boolean isCardCenter) throws Exception{
        Map<String,Object> insertMap = new HashMap<>();
        creatDatasetMap(businessInputMap,metaMap,insertMap,isCardCenter);
        return insertMap;
    }
    private static void creatDatasetMap(Map<String,Object> requestMap,
    		Map<String,MClass> metaMap,
    		Map<String,Object> insertMap,
    		boolean isCardCenter) throws Exception{
        Set<Map.Entry<String, Object>> entries = requestMap.entrySet();
        for(Map.Entry<String,Object> outEntity : entries){//外部信息，账单信息，输出信息，拓展信息
            if(outEntity.getKey().equals("SystemOutInfo")){
               continue;
            }
            Map<String, Object> datasetMap = (Map<String, Object>) outEntity.getValue();
            convertInsertMap(outEntity.getKey(),datasetMap,metaMap,insertMap);
            //如果不是卡中心，  外部可能传入与数据模型不相关的数据，但是这部分数据也需要传入规则入参
            if(!isCardCenter && !metaMap.containsKey(outEntity.getKey())) {
                insertMap.put(outEntity.getKey(), outEntity.getValue());
            }
        }
    }

    private static void convertInsertMap(String datasetKey,Map<String,Object> datasetMap,Map<String,MClass>metaMap,Map<String,Object> insertMap) throws Exception{
        Set<Map.Entry<String, Object>> entries = datasetMap.entrySet();
        if(entries==null || entries.size()==0) {
        	insertMap.put(datasetKey, new HashMap<String,Object>());
        }
        for(Map.Entry<String,Object> datasetEntry : entries){//基本信息
            String key = datasetEntry.getKey();
            Map<String,Object> sunMap = new HashMap<>();
            if(datasetEntry.getValue() instanceof  Map){
                Map<String,Object> paramsMap = (Map<String,Object>)datasetEntry.getValue();
                insertMap.put(key,sunMap);
                parseDefaultValue(key,paramsMap,metaMap,sunMap);
            }else{
                insertMap.put(datasetKey,sunMap);
                parseDefaultValue(datasetKey,datasetMap,metaMap,sunMap);
            }
        }
    }

    private static void parseDefaultValue(String key ,Map<String,Object> paramsMap,Map<String,MClass> metaMap,Map<String,Object> sunMap) throws Exception{
        MClass mClass = metaMap.get(key);
        if(mClass==null){
            return;//如没有对应key值得数据集，不需要解析
        }
//        Set<String> set = mClass.getFieldMap().keySet();
        Iterator<String> iterator = paramsMap.keySet().iterator();
        while(iterator.hasNext()){
            String fieldKey = iterator.next();
            MField mField = mClass.getFieldMap().get(fieldKey);
            Object paramValue = paramsMap.get(mField.getName());
            if(paramValue!=null&&StringUtils.isNotBlank(paramValue.toString())){
                 sunMap.put(mField.getName(),createObject(mField,paramValue.toString(),mClass.getName()));
            }else{//为默认值
                sunMap.put(mField.getName(),mField.getDefaultValue());
            }
        }
    }

    private static Object createObject(MField mField, String attrValue,String className) throws Exception {
    	try {
	        if (attrValue != null) {
	            if ("String".equalsIgnoreCase(mField.getType())) {
	                return attrValue;
	            } else if ("Long".equalsIgnoreCase(mField.getType())) {
	                return "".equals(attrValue) ? 0L : Double.valueOf(attrValue).longValue();
	            } else if ("Double".equalsIgnoreCase(mField.getType())) {
	                return "".equals(attrValue) ? 0.0D : Double.parseDouble(attrValue);
	            } else if ("Integer".equalsIgnoreCase(mField.getType())) {
	                return "".equals(attrValue) ? 0 : Integer.parseInt(attrValue);
	            } else if ("FLoat".equalsIgnoreCase(mField.getType())) {
	                return "".equals(attrValue) ? 0.0F : Float.parseFloat(attrValue);
	            } else if ("Date".equalsIgnoreCase(mField.getType())) {
	                return attrValue;
	            } else if ("Boolean".equalsIgnoreCase(mField.getType())) {
	                return !"true".equalsIgnoreCase(attrValue) && !"1".equalsIgnoreCase(attrValue) && !"y".equalsIgnoreCase(attrValue) && !"yes".equalsIgnoreCase(attrValue) ? Boolean.FALSE : Boolean.TRUE;
	            } else {
	                return null;
	            }
	        } else if ("String".equalsIgnoreCase(mField.getType())) {
	            return "";
	        } else if ("Long".equalsIgnoreCase(mField.getType())) {
	            return null;
	        } else if ("Double".equalsIgnoreCase(mField.getType())) {
	            return null;
	        } else if ("Integer".equalsIgnoreCase(mField.getType())) {
	            return null;
	        } else if ("Float".equalsIgnoreCase(mField.getType())) {
	            return null;
	        } else if ("Date".equalsIgnoreCase(mField.getType())) {
	            return mField.getDefaultValue();
	        } else {
	            return "Boolean".equalsIgnoreCase(mField.getType()) ? false : null;
	        }
       	}catch(Exception e) {
       		throw new Exception("【"+className+"."+mField.getName()+"】字段数据类型转换失败,请检查传入类型和数据模型中配置的是否一致");
       	}
    }

    /**
     * 将insertMap得值填充到固定的报文格式
     * @param insertMap
     * @param requestJson
     * @return
     * @throws Exception
     */
    public static String mapConverJson(Map<String,Object> insertMap,Map<String,Object> requestMap) throws Exception{
    	if(!requestMap.containsKey("SystemOutInfo")) {
    		requestMap.put("SystemOutInfo", new HashMap<String,Object>());
    	}
        Set<Map.Entry<String, Object>> entries = requestMap.entrySet();
        for(Map.Entry<String,Object> entry : entries){
            convertRequestMap(entry.getKey(),requestMap,insertMap);
        }
        String responseJson = JSON.toJSONString(requestMap);;
        return  responseJson;
    }
    public static void mapConverJson_1(Map<String,Object> insertMap,Map<String,Object> requestMap) throws Exception{
    	if(!requestMap.containsKey("SystemOutInfo")) {
    		requestMap.put("SystemOutInfo", new HashMap<String,Object>());
    	}
        Set<Map.Entry<String, Object>> entries = requestMap.entrySet();
        for(Map.Entry<String,Object> entry : entries){
            convertRequestMap(entry.getKey(),requestMap,insertMap);
        }
    }
    private static void convertRequestMap(String key,Map<String,Object> requestMap,Map<String,Object> insertMap){
        if(!key.equals("SystemOutInfo")){
            Map<String,Object> paramMap = (Map<String,Object>)requestMap.get(key);
            Set<Map.Entry<String, Object>> entries = paramMap.entrySet();
            for(Map.Entry<String, Object> entry : entries){
                String paramKey = entry.getKey();
                if(entry.getValue() instanceof Map){
                    Map<String,Object> paramValueMap = (Map<String,Object>)entry.getValue();
                    Map<String,Object> insertValueMap = (Map<String,Object>)insertMap.get(paramKey);
                    if(insertValueMap==null)
                    	continue;
                    for(Map.Entry<String, Object> eny : paramValueMap.entrySet()){
                    	if(insertValueMap.containsKey(eny.getKey()))
                    		paramValueMap.put(eny.getKey(),insertValueMap.get(eny.getKey()));
                    }
                }else{
                    Map<String,Object> insertValueMap = (Map<String,Object>)insertMap.get(key);
                    if(insertValueMap!=null && insertValueMap.containsKey(entry.getKey()))
                    	paramMap.put(entry.getKey(),insertValueMap.get(entry.getKey()));
                }

            }
        }else{
            Map<String,Object> sysValue = (Map<String, Object>) requestMap.get("SystemOutInfo");
            
            Map<String, Object> rulesys = (Map<String, Object>) insertMap.get("SystemOutInfo");
            List<Map<String, Object>> ruleExecutResultList = (List<Map<String, Object>>) rulesys.get("ruleExecutResultList");
            sysValue.put("invokeId", rulesys.get("invokeId"));
            sysValue.put("entryPoint", rulesys.get("entryPoint"));
            sysValue.put("projectCode", rulesys.get("projectCode"));
            sysValue.put("isSuccess", rulesys.get("isSuccess"));
            sysValue.put("exceptionType", rulesys.get("exceptionType"));
            sysValue.put("exception", rulesys.get("exception"));
            sysValue.put("invokeTimes", rulesys.get("invokeTimes"));
            
            Map<String,Object> SystemOutInfo = parseRuleLog(ruleExecutResultList,sysValue,rulesys.get("invokeId").toString(),insertMap);
            requestMap.put("SystemOutInfo",SystemOutInfo);
        }
    }
    private static Map<String,Object> parseRuleLog(List<Map<String, Object>> ruleExecutResultList,
    		Map<String,Object> retMap,
    		String invokeId,
    		Map<String,Object> insertMap){
		if(retMap==null) {
			retMap = new HashMap<>();
		}
		Map<String,Object> ProcessingInfo = (Map<String, Object>) retMap.get("ProcessingInfo");
		if(ProcessingInfo==null) {
			ProcessingInfo = new HashMap<>();
			retMap.put("ProcessingInfo", ProcessingInfo);
		}
		List<Map<String,Object>> FlowHistory = null;
		Object FlowHistoryObj= ProcessingInfo.get("FlowHistory");
		if(FlowHistoryObj==null || FlowHistoryObj.toString().equals("-99")) {
			FlowHistory = new ArrayList<>();
			ProcessingInfo.put("FlowHistory", FlowHistory);
		}else {
			FlowHistory = (List<Map<String, Object>>) ProcessingInfo.get("FlowHistory");
		}
		Map<String,Object> ProcessingInfoMap = new HashMap<>();
		FlowHistory.add(ProcessingInfoMap);
		ProcessingInfoMap.put("ruleExecuteList", ruleExecutResultList);
		
		Map<String,Object> ResponseInfo = (Map<String, Object>) retMap.get("ResponseInfo");
		if(ResponseInfo==null) {
			ResponseInfo = new HashMap<>();
		}
		String AllReasonCodeStr = (String) ResponseInfo.get("AllReasonCode");
		String AllRuleScoreStr = (String) ResponseInfo.get("AllRuleScore");
		String AllRuleListStr = (String) ResponseInfo.get("AllRuleList");
		String AllRuleEntryStr = (String) ResponseInfo.get("AllRuleEntry");
		
		if(AllReasonCodeStr==null || "-99".equals(AllReasonCodeStr)) {AllReasonCodeStr="[]";}
		if(AllRuleScoreStr==null || "-99".equals(AllRuleScoreStr)) {AllRuleScoreStr="[]";}
		if(AllRuleListStr==null || "-99".equals(AllRuleListStr)) {AllRuleListStr="[]";}
		if(AllRuleEntryStr==null || "-99".equals(AllRuleEntryStr)) {AllRuleEntryStr="[]";}
		
		List<String> AllReasonCode = JSON.parseArray(AllReasonCodeStr,String.class);
		List<String> AllRuleScore = JSON.parseArray(AllRuleScoreStr,String.class);
		List<String> AllRuleList = JSON.parseArray(AllRuleListStr,String.class);
		List<String> AllRuleEntry = JSON.parseArray(AllRuleEntryStr,String.class);
		
		List<String> tmp0 = new ArrayList<>();
		List<String> tmp1 = new ArrayList<>();
		List<String> tmp2 = new ArrayList<>();
		List<String> tmp3 = new ArrayList<>();
		List<String> flowList = new ArrayList<>();
		Map<String,String> exist = new HashMap<>();
		for (Map<String, Object> map : ruleExecutResultList) {
			if(null==map.get("type"))
				continue;
			String type = map.get("type").toString();
			if("policyrulegroup".equals(type)) {
				String code = map.get("group").toString();
				if(exist.containsKey(code))
					continue;
				exist.put(code, code);
				Map<String,Object> groupMap = (Map<String, Object>) insertMap.get(code);
				if(groupMap==null)
					continue;
				
				addToTmp(tmp0,groupMap.get("activeEntryList"),true);
				addToTmp(tmp1,groupMap.get("activeList"),true);
				addToTmp(tmp2,groupMap.get("ruleScoreSum"),false);
				addToTmp(tmp3,groupMap.get("reasonList"),true);
			}
			if("ruleFlow".equals(type)) {
				flowList.add(map.get("DecisionFlowName").toString());
			}
		}
		ProcessingInfoMap.put("DecisionFlowName", String.join(",", flowList));
		ProcessingInfoMap.put("invokeId", invokeId);
		ProcessingInfoMap.put("RuleEntry", tmp0);
		ProcessingInfoMap.put("RuleList", tmp1);
		ProcessingInfoMap.put("RuleScore", tmp2);
		ProcessingInfoMap.put("ReasonCode", tmp3);
		
		AllRuleEntry.addAll(tmp0);
		AllRuleList.addAll(tmp1);
		AllRuleScore.addAll(tmp2);
		AllReasonCode.addAll(tmp3);
		
		ResponseInfo.put("AllReasonCode",JSON.toJSONString(AllReasonCode));
		ResponseInfo.put("AllRuleScore", JSON.toJSONString(AllRuleScore));
		ResponseInfo.put("AllRuleList", JSON.toJSONString(AllRuleList));
		ResponseInfo.put("AllRuleEntry", JSON.toJSONString(AllRuleEntry));
		
		retMap.put("ResponseInfo", ResponseInfo);
		retMap.put("ProcessingInfo", ProcessingInfo);
		return retMap;
	}
	private static void addToTmp(List<String> tmpList,Object value,Boolean isList) {
		if(isList) {
			if(value!=null) {
				List<String> list = (List<String>) value;
				for (String string : list) {
					if(!tmpList.contains(string) && value!=null && !"null".equals(string)) {
						tmpList.add(string);
					}
				}
			}
		}else {
			if(value!=null && !"null".equals(value)&&!tmpList.contains(value.toString())) {
				tmpList.add(value.toString());
			}
		}
	}
}